As funções geralmente seguem o fluxo convencional de processar, retornar valores e encerrar. Geradores funcionam de forma similar, porém lembram o estado do processamento entre as chamadas, permanecendo em memória e retornando o próximo item esperado quando ativados.
Os geradores apresentam várias vantagens em relação às funções convencionais:
Geradores geralmente são evocados através de um laço for. A sintaxe é semelhante a da função tradicional, só que a instrução yield substitui o return. A nova cada iteração, yield retorna o próximo valor.
Exemplo:
In [4]:
def gen_pares():
"""
Gera números pares entre 0 e 20
"""
i = 0
while i <= 20:
yield i
i += 2
# Mostra cada número e passa para o próximo
for n in gen_pares():
print n
Outro exemplo:
In [7]:
import os
# Encontra arquivos recursivamente
def find(path='.'):
for item in os.listdir(path):
fn = os.path.normpath(os.path.join(path, item))
if os.path.isdir(fn):
for f in find(fn):
yield f
else:
yield fn
# A cada iteração, o gerador devolve
# um novo nome de arquivo
for fn in find():
print fn
Existem vários geradores que fazem parte da própria linguagem, como o builtin xrange(). Além disso, no módulo itertools, estão definidos vários geradores úteis.
Para converter a saída do gerador em uma lista:
lista = list(gerador())
Assim, todos os itens serão gerados de uma vez.
In [1]:
Out[1]: